package cn.izeno.wx.web

import cn.izeno.wx.models.web.*
import cn.izeno.wx.service.Web
import cn.izeno.wx.service.WebWxApp
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.subjects.PublishSubject
import okhttp3.ResponseBody
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.*
import java.util.logging.Logger

/**
 * [syncCheck] 心跳检测
 */
class MessageReceiver : Runnable {

  override fun run() {
    var err = 0
    var heartMsg = 0L

    while (running) {
      syncCheck().flatMap {
        when (it.selector) {
          2, 6, 7 -> {
            Web.service.sync()
          }
          else -> Observable.empty<SyncRes>()
        }
      }.subscribe({
        WebWxApp.syncKey = it.syncCheckKey
        if (it.addMsgCount > 0) {
          it.addMsgList.forEach { msg ->
            when (msg.msgType) {
              1 -> txtMsg.onNext(msg)
              3, 34, 43 -> fileMsg.onNext(msg)
              49 -> if (msg.mediaId.isNotEmpty()) fileMsg.onNext(msg)
              Message.TYPE_SYSTEM -> sysMsg.onNext(msg)
            }
          }
        }

        if (it.modContactCount > 0) {
          it.modContactList.forEach { contact -> contactSubject.onNext(contact) }
        }
        err = 0

      }, {
        err++
        logger.warning("发生错误,休息3s ---> " + it.message)
        if (err > 10) {
          logger.warning("发生连续错误, 结束网页微信")
          WebWxApp.exit(-1)
          running = false
        } else {
          Thread.sleep(3000)
        }
      })

      // 1m间隔时间发送心跳消息， 阻止微信离线
      val now = System.currentTimeMillis()
      if (now - heartMsg > 60000) {
        this.heartMsg()
        heartMsg = now
      }
    }
  }

  private fun syncCheck(): Observable<CheckSyncRes> {


    return Web.service.syncCheck()
        .doOnNext {
          when (it.retcode) {
            CheckSyncRes.LOGIN_OTHER, CheckSyncRes.LOGOUT -> {
              running = false
              WebWxApp.exit(-1)
              logger.info("登录信息失效, 停止接收消息")
            }
          }
        }
  }

  private fun heartMsg() {
    val date = SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(Date());
    val msg = TextMessage("消息同步 ---> $date", "filehelper")
    MessageSender.send(msg)
  }

  companion object {
    private val logger = Logger.getLogger("cn.izeno.wx.web.MessageReceiver")

    @Volatile
    private var running = false

    val txtMsg = PublishSubject.create<Message>()

    val roomTxtMsg = txtMsg.filter { it.fromUserName.startsWith("@@") }.map { msg ->
      val roomTxt = RoomTxtMsg()

      roomTxt.msgId = msg.msgId

      // 群昵称
      val roomUsername = msg.fromUserName
      roomTxt.room = ContactManager.getContactName(roomUsername)

      val sep = msg.content.indexOf(":<br/>")
      val fromUsername = msg.content.substring(0, sep)
      roomTxt.nickname = ContactManager.getContactName(fromUsername, roomUsername)
      roomTxt.content = msg.content.substring(sep + 6, msg.content.length)

      roomTxt
    }

    val fileMsg = PublishSubject.create<Message>()

    // 系统消息
    val sysMsg = PublishSubject.create<Message>()

    // 红包消息
    val groupRedMsg = sysMsg.filter { it.content == "收到红包，请在手机上查看" }

    val contactSubject = PublishSubject.create<Member>()

    fun start() {
      if (!running) {
        running = true
        Thread(MessageReceiver()).start()
      }
    }

    /**
     * @param path 文件存储路径
     */
    fun saveFile(path: String = System.getProperty("user.dir")): ((Message) -> Observable<String>) {

      return { message ->
        when (message.msgType) {
          3 -> Web.service.getMsgImg(msgId = message.msgId)
          34 -> Web.service.getVoice(msgId = message.msgId)
          43 -> Web.service.getVideo(msgId = message.msgId)
          49 -> Web.service.getMedia(mediaId = message.mediaId, fromUsername = message.fromUserName, filename = message.filename)
          else -> Observable.empty<ResponseBody>()
        }.map { body ->
          var filename = ""
          try {
            val suffix = if (message.msgType == 49) {
              message.filename
            } else {
              "." + body.contentType().toString().split("/")[1]
            }

            File(path).mkdirs()

            val date = SimpleDateFormat("yyyyMMdd_").format(Date())

            filename = path + date + message.msgId + suffix

            val fileOS = FileOutputStream(filename)
            val buffer = ByteArray(4096)
            var count: Int
            val io = body.byteStream()
            do {
              count = io.read(buffer)
              if (count > 0) {
                fileOS.write(buffer, 0, count)
              }
            } while (count > 0)
            io.close()

            fileOS.flush()
            fileOS.close()

          } catch (e: Exception) {
            filename = "文件保存失败"
          }

          filename
        }
      }
    }
  }
}